use tauri::Window;
use tokio::sync::Mutex;

use crate::error::{AppErr, ToResult, Wrap};

use self::serial_port::{SerialPort, SharedPort};

mod proto;
mod serial_port;

static GLOBAL_PORT: Mutex<Option<SharedPort>> = Mutex::const_new(Option::None);

#[tauri::command]
pub fn active_port_name() -> Result<Vec<String>, AppErr> {
    tokio_serial::available_ports()
        .wrap()?
        .into_iter()
        .map(|item| item.port_name)
        .collect::<Vec<String>>()
        .to()
}

#[tauri::command]
pub async fn serial_port_is_open() -> Result<bool, AppErr> {
    GLOBAL_PORT.lock().await.is_some().to()
}

#[tauri::command]
pub async fn serial_port_open(name: String, baud_date: u32, window: Window) -> Result<(), AppErr> {
    let mut lock = GLOBAL_PORT.lock().await;
    if let Some(port) = lock.as_ref() {
        port.close();
    }
    let port = SerialPort::new(window, &name, baud_date)?;
    *lock = Some(port);

    Ok(())
}

#[tauri::command]
pub async fn serial_port_close() -> Result<(), AppErr> {
    let mut lock = GLOBAL_PORT.lock().await;
    if let Some(port) = lock.as_ref() {
        port.close();
    }
    *lock = None;
    Ok(())
}

#[tauri::command]
pub async fn serial_port_write(buf: Box<[u8]>) -> Result<(), AppErr> {
    let lock = GLOBAL_PORT.lock().await;
    match lock.as_ref() {
        Some(port) => port.write(&buf).await?,
        None => return AppErr::Proto("串口没有打开").to(),
    };
    Ok(())
}
